﻿using GalaSoft.MvvmLight.Messaging;
using JiveMessenger.Helpers;
using JiveMessenger.Models;
using JiveMessenger.Settings;
using JiveMessenger.User;
using JmShared;
using Microsoft.Phone.Tasks;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace JiveMessenger.CustomControls
{
    public class JiveRichTextBox : RichTextBox
    {
        //private const string UrlPattern = @"(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?";

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(JiveRichTextBox), new PropertyMetadata(default(string), TextPropertyChanged));

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        private static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var text = dependencyPropertyChangedEventArgs.NewValue.ToString();

            var richTextBox = (JiveRichTextBox)dependencyObject;
            MessageModel msg = richTextBox.DataContext as MessageModel;
            if (msg == null)
                return;

            richTextBox.Blocks.Clear();
          
            Dictionary<int, object> objects = SplitUrlAndEmoticons(text, msg.UserID);
            var paragraph = MakeParagraph(objects);

            richTextBox.Blocks.Add(paragraph);
        }

        private static Paragraph MakeParagraph(Dictionary<int, object> objects)
        {
            Paragraph p = new Paragraph();
            foreach (KeyValuePair<int, object> kvp in objects)
            {

                if (kvp.Value.GetType() == typeof(string))
                {
                    Run r = new Run();

                    r.Text = kvp.Value.ToString();

                    p.Inlines.Add(r);
                }
                else if (kvp.Value.GetType() == typeof(Hyperlink))
                {
                    Hyperlink hl = kvp.Value as Hyperlink;

                    string imgurId = GetImgurId(hl.NavigateUri);
                    if (!String.IsNullOrEmpty(imgurId) && StaticSettings.IsWifiEnabled)
                    {

                        string thumbUrl = String.Format("Http://i.imgur.com/{0}b.png", imgurId);
                        WebClient client = new WebClient();

                        InlineUIContainer ui = new InlineUIContainer();
                        KeyValuePair<Hyperlink, InlineUIContainer> kv = new KeyValuePair<Hyperlink, InlineUIContainer>(hl, ui);

                        client.OpenReadCompleted += client_OpenReadCompleted;
                        Image dummy = new Image()
                        {
                            Source = new BitmapImage(new Uri("/Assets/imagedummy_160x160.png", UriKind.Relative)),
                            Stretch = Stretch.Uniform
                        };

                        ui.Child = dummy;
                        p.Inlines.Add(ui);

                        client.OpenReadAsync(new Uri(thumbUrl), kv);
                    }
                    else
                    {
                        p.Inlines.Add(hl);
                    }
                }
                else if (kvp.Value.GetType() == typeof(Image))
                {
                    Image i = (Image)kvp.Value;

                    InlineUIContainer c = new InlineUIContainer();
                    c.Child = i;
                    p.Inlines.Add(c);

                }
            }
            return p;
        }

        private static void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            WebClient client = sender as WebClient;

            //  string imgUrl = String.Format("Http://i.imgur.com/{0}.png",e.UserState);
            KeyValuePair<Hyperlink, InlineUIContainer> kvp = (KeyValuePair<Hyperlink, InlineUIContainer>)e.UserState;

            Hyperlink link = kvp.Key;
            InlineUIContainer ui = kvp.Value;

            if (e.Cancelled || e.Error != null)
            {
                RichTextBox rtb = new RichTextBox();
                Paragraph p = new Paragraph();
                p.Inlines.Add(link);
                rtb.Blocks.Add(p);
                ui.Child = rtb;
            }
            var stream = e.Result;
            Image img = new Image
            {
                Stretch = System.Windows.Media.Stretch.Uniform,
                //Width = 50,
                //Height = 50,

            };
            try
            {
                var bi = new BitmapImage();
                bi.SetSource(stream);
                img.Source = bi;
                ui.Child = img;
                // this.currentParagraph.Inlines.Add(new InlineUIContainer() { Child = img });
                img.Tap += (s, args) =>
                {
                    var task = new WebBrowserTask() { Uri = link.NavigateUri };
                    task.Show();
                    args.Handled = true;
                };
                img.Hold += (s, args) =>
                {
                    Messenger.Default.Send("Not yet implemented");
                    args.Handled = true;
                };
            }
            catch (Exception err)
            {
                Debug.WriteLine("Error opening image:{0}", err);
            }
            finally
            {
                stream.Close();
                client.OpenReadCompleted -= client_OpenReadCompleted;
            }
        }

        private static string GetImgurId(Uri link)
        {
            string id = null;
            Regex imgurRegex = new Regex(@"http://(?:i\.imgur\.com/(?<id>.*?)\.(?:jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF).*|imgur\.com/(?:gallery/)?(?<id>.*))$");
            Match imgurMatch = imgurRegex.Match(link.AbsoluteUri);
            if (imgurMatch.Success)
                id = imgurMatch.Groups["id"].Value;

            if (id != null && id.Contains("a/"))
                id = null;
            if (id != null && id.Contains("/"))
            {
                id = id.Substring(id.LastIndexOf("/", System.StringComparison.Ordinal));
                id = id.Replace("/", "");
            }
            if (link.AbsoluteUri.ToLower().Contains("/gallery"))
                id = null;
            return id;
        }
        private static Dictionary<int, object> SplitUrlAndEmoticons(string text, string userID)
        {
            Dictionary<int, object> objects = new Dictionary<int, object>();
            Regex UrlMatch = new Regex(@"(((file|gopher|news|nntp|telnet|http|ftp|https|ftps|sftp)://)|(www\.))+(([a-zA-ZÆæÅåØø0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(/[a-zA-ZÆæÅåØø0-9\&amp;%_\./-~-\(\),\'\[\]+\=#]*)?");//new Regex(HyperLinkRegex);
            MatchCollection col = UrlMatch.Matches(text);
            Dictionary<int, TextMatch> foundTextMatches = new Dictionary<int, TextMatch>();
            foreach (Match m in col)
            {
                foundTextMatches.Add(m.Index, new TextMatch() { type = TextMatchType.URL, Text = m.Value });
            }

            Dictionary<string, string> defaultEmoticons = Client.Instance.GetEmoticons(userID, true, false,false);
            string[] defaultKeys = defaultEmoticons.Keys.ToArray();
            foreach (string str in defaultKeys)
            {
                if (String.IsNullOrEmpty(defaultEmoticons[str]))
                    continue;
                List<int> indexes = text.AllIndexesOf(str);
                foreach (int i in indexes)
                {
                    foundTextMatches.Add(i, new TextMatch() { type = TextMatchType.DefaultEmoticon, Text = str });
                }
            }
            Dictionary<string, string> customEmoticons;
            if (System.ComponentModel.DesignerProperties.IsInDesignTool)
            {
                customEmoticons = new Dictionary<string, string>();
            }
            else
            {
                customEmoticons = Client.Instance.GetEmoticons(userID, false, true,false);
                string[] customKeys = customEmoticons.Keys.ToArray();
                foreach (string str in customKeys)
                {
                    if (String.IsNullOrEmpty(customEmoticons[str]))
                        continue;
                    List<int> indexes = text.AllIndexesOf(str);
                    foreach (int i in indexes)
                    {
                        if (!foundTextMatches.ContainsKey(i))
                            foundTextMatches.Add(i, new TextMatch() { type = TextMatchType.CustomEmoticon, Text = str });
                    }
                }
            }
            int startindex = 0;

            foreach (KeyValuePair<int, TextMatch> kvp in foundTextMatches.OrderBy(x => x.Key))
            {
                if (kvp.Key < startindex)
                    continue;

                string leading = text.Substring(startindex, kvp.Key - startindex);
                if (!String.IsNullOrEmpty(leading))
                    objects.Add(startindex, leading);
                switch (kvp.Value.type)
                {
                    case TextMatchType.CustomEmoticon:
                        {
                            string emoticon = kvp.Value.Text;

                            var savePath = customEmoticons[emoticon];
                            Stopwatch watch = Stopwatch.StartNew();
                            Image image = StaticMethods.LoadImageFromIsolatedStorage(savePath);
                            Debug.WriteLine(string.Format("Time to load custom emoticon {0}: {1}ms", emoticon, watch.ElapsedMilliseconds));
                            image.Stretch = Stretch.Uniform;
                            //image.Tag = emoticon;
                            int width = 0;
                            int height = 0;
                            BitmapImage imgSource = image.Source as BitmapImage;

                            if (imgSource != null)
                            {
                                width = imgSource.PixelWidth;
                                height = imgSource.PixelHeight;
                            }
                            image.Width = width > 0 ? width * 1.5 : 28;
                            image.Height = height > 0 ? height * 1.5 : 28;
                            objects.Add(kvp.Key, image);
                            break;
                        }
                    case TextMatchType.DefaultEmoticon:
                        {
                            string emoticon = kvp.Value.Text;
                            Stopwatch watch = Stopwatch.StartNew();
                            var savePath = "/Assets/DefaultEmoticons/";
                            Uri u = new Uri(savePath + defaultEmoticons[emoticon], UriKind.RelativeOrAbsolute);
                            Image image = new Image
                            {
                                Source = new BitmapImage(u),
                                Stretch = Stretch.Uniform,
                            };
                            Debug.WriteLine(string.Format("Time to load default emoticon {0}: {1}ms", emoticon, watch.ElapsedMilliseconds));
                            int width = 0;
                            int height = 0;
                            BitmapImage imgSource = image.Source as BitmapImage;
                            if (imgSource != null)
                            {
                                width = imgSource.PixelWidth;
                                height = imgSource.PixelHeight;
                            }
                            image.Width = width > 0 ? width * 1.5 : 28;
                            image.Height = height > 0 ? height * 1.5 : 28;
                            //image.Tag = emoticon;
                            objects.Add(kvp.Key, image);
                            break;
                        }
                    case TextMatchType.URL:
                        {
                            string url = kvp.Value.Text;
                            if (url.ToLower().StartsWith("www"))
                                url = "http://" + url;
                            Hyperlink link = new Hyperlink()
                            {
                                NavigateUri = new Uri(url, UriKind.Absolute),
                                TargetName = "_blank"
                            };
                            link.Inlines.Add(kvp.Value.Text);
                            link.Foreground = new SolidColorBrush(Color.FromArgb(1, 255, 0, 0));
                            objects.Add(kvp.Key, link);
                            break;
                        }
                }
                startindex = kvp.Key + kvp.Value.Text.Length;
            }


            if (foundTextMatches.Count == 0)
                objects.Add(0, text);
            else
            {
                string lastText = text.Substring(startindex, text.Length - startindex);
                if (!String.IsNullOrEmpty(lastText))
                    objects.Add(startindex, lastText);
            }
            return objects;
        }
        private enum TextMatchType
        {
            URL,
            CustomEmoticon,
            DefaultEmoticon
        }
        private struct TextMatch
        {
            public TextMatchType type { get; set; }
            public string Text { get; set; }
            public override string ToString()
            {
                return Text;
            }
        }
    }
}
